package com.github.shiqiyue.app.modules.dbms.service.impl;

import cn.hutool.crypto.symmetric.SymmetricAlgorithm;
import cn.hutool.crypto.symmetric.SymmetricCrypto;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.shiqiyue.app.api.sapi.controller.dbms.req.DatabasePageReq;
import com.google.common.collect.Maps;
import com.github.shiqiyue.app.common.exception.BusinessException;
import com.github.shiqiyue.app.modules.dbms.entity.Database;
import com.github.shiqiyue.app.modules.dbms.entity.DatabaseHistory;
import com.github.shiqiyue.app.modules.dbms.mapper.DatabaseMapper;
import com.github.shiqiyue.app.modules.dbms.service.IDatabaseHistoryService;
import com.github.shiqiyue.app.modules.dbms.service.IDatabaseService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.SimpleDriverDataSource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.sql.DataSource;
import java.sql.Driver;
import java.util.Map;

/**
 * <p>
 * 数据库 服务实现类
 * </p>
 *
 * @author wenyao.wu
 * @since 2019-08-06
 */
@Slf4j
@Service
public class DatabaseServiceImpl extends ServiceImpl<DatabaseMapper, Database> implements IDatabaseService {

    @Autowired
    private IDatabaseHistoryService databaseHistoryService;

    Map<Long, JdbcTemplate> jdbcTemplateCache = Maps.newConcurrentMap();

    /***
     * 对称加密 key
     */
    private byte[] key = {-43, 118, -65, 14, -108, -2, -5, -68, 118, 21, 37, 2, 97, -9, -29, 97, -88, 13, -118, 124, -94, 76, 70, 21};

    /***
     * 对称加密对象
     */
    SymmetricCrypto des = new SymmetricCrypto(SymmetricAlgorithm.DESede, key);

    /***
     * 加密密码
     * @param password
     * @return
     */
    private String encryptPassword(String password) {
        String encryptHex = des.encryptHex(password);
        return encryptHex;
    }

    /***
     * 解密密码
     * @param password
     * @return
     */
    private String decryptPassword(String password) {
        return des.decryptStr(password);
    }

    @Override
    public IPage<Database> page(DatabasePageReq databasePageReq) {
        return baseMapper.page(new Page<Database>(databasePageReq.getCurrent(), databasePageReq.getSize()), databasePageReq);
    }

    @Override
    public Database getDatabaseById(Long id) {
        return baseMapper.getDetailById(id);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void add(Database database, Long operatorId) {
        database.setAddUserId(operatorId);
        database.setEditUserId(operatorId);
        database.setPassword(encryptPassword(database.getPassword()));
        baseMapper.insert(database);
        databaseHistoryService.addHistory(database.getId(),
                String.format("数据库名称:%s,用户名:%s,数据库链接:%s", database.getName(), database.getUsername(), database.getUrl()),
                DatabaseHistory.Type.ADD,
                operatorId);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void edit(Database database, Long operatorId) {
        Database updateParam = new Database();
        updateParam.setId(database.getId());
        updateParam.setEditUserId(operatorId);
        updateParam.setDbType(database.getDbType());
        updateParam.setName(database.getName());
        updateParam.setRemark(database.getRemark());
        updateParam.setUrl(database.getUrl());
        updateParam.setUsername(database.getUsername());
        if (StringUtils.isNotBlank(database.getPassword())) {
            updateParam.setPassword(encryptPassword(database.getPassword()));
        }
        baseMapper.updateById(updateParam);
        databaseHistoryService.addHistory(database.getId(),
                String.format("数据库名称:%s,用户名:%s,数据库链接:%s", database.getName(), database.getUsername(), database.getUrl()),
                DatabaseHistory.Type.EDIT,
                operatorId);
    }

    @Override
    public JdbcTemplate getJdbcTemplateByDatabaseId(Long databaseId) {
        Database database = this.getById(databaseId);
        if (database == null) {
            throw new BusinessException("数据不存在");
        }
        JdbcTemplate jdbcTemplate = jdbcTemplateCache.get(databaseId);
        if (jdbcTemplate != null) {
            return jdbcTemplate;
        }
        try {
            DataSource datasource = new SimpleDriverDataSource((Driver) Class.forName("com.mysql.cj.jdbc.Driver").newInstance(),
                    database.getUrl(),
                    database.getUsername(),
                    decryptPassword(database.getPassword()));
            jdbcTemplate = new JdbcTemplate(datasource);
            jdbcTemplate.execute("select 1");
            jdbcTemplateCache.put(databaseId, jdbcTemplate);
            return jdbcTemplate;
        } catch (Exception e) {
            throw new BusinessException(e);
        }
    }
}
